#include "MCArcVisual.h"
#include <MCMathUtils.h>
#include <MCGripPoint.h>
#include <MCSettings.h>
#include <MCCircle2D.h>

MCArcVisual::MCArcVisual(ICanvas *presenter, const MCArc2D &arc) :
    MCGraphicsItem(presenter),
    _arcModel(arc)
{
    initGrips();
}

void MCArcVisual::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    setPainter(painter);

    MCArc2D arc = transformed();
    drawArc(arc.center(), arc.radius(), arc.startAngle(), arc.endAngle());
}

QPainterPath MCArcVisual::shape() const
{
    QPainterPath path;

    MCPoint2D center = transformed().center();
    double radius = transformed().radius();
    auto draggingZone = MCSettings::CircleClickableZone;

    path.addEllipse(QPointF(center.x, center.y), draggingZone, draggingZone);
    path.addEllipse(QPointF(center.x, center.y), radius + draggingZone, radius + draggingZone);
    path.addEllipse(QPointF(center.x, center.y), radius - draggingZone, radius - draggingZone);

    return path;
}

bool MCArcVisual::contains(const QPointF &point) const
{
    MCArc2D model = _arcModel;
    MCPoint2D center = model.center();
    double d = std::sqrt(std::pow(point.x() - center.x, 2) + std::pow(point.y() - center.y, 2));

    return d < model.radius();
}

MCArc2D MCArcVisual::arc() const
{
    return _arcModel;
}

void MCArcVisual::update(const MCPoint2D &center, double radius, double startAngle, double endAngle)
{
    _arcModel = MCArc2D(center, radius, startAngle, endAngle);
}

void MCArcVisual::update(const MCArc2D &arc)
{
    _arcModel = arc;
}

void MCArcVisual::setGripAt(IGripPoint *grip, const MCPoint2D &pos)
{
    if (grip->index() == 0)
    {
        _arcModel.setPositionAt(pos);
    }
    else if (grip->index() == 1)
    {
        MCVector2 curVec = (MCVector2)(pos - _arcModel.center());
        double startAngle = MCMathUtils::normalizeAngle(MCVector2(1, 0).clockwiseAngle(curVec));
        _arcModel = MCArc2D(_arcModel.center(), _arcModel.radius(), startAngle, _arcModel.endAngle());
    }
    else if (grip->index() == 2)
    {
        MCVector2 curVec = (MCVector2)(pos - _arcModel.center());
        double endAngle = MCMathUtils::normalizeAngle(MCVector2(1, 0).clockwiseAngle(curVec));
        _arcModel = MCArc2D(_arcModel.center(), _arcModel.radius(), _arcModel.startAngle(), endAngle);
    }

    //// https://stackoverflow.com/questions/22791951/algorithm-to-find-an-arc-its-center-radius-and-angles-given-3-points
    //// https://math.stackexchange.com/questions/213658/get-the-equation-of-a-circle-when-given-3-points
    //else if (grip->index() == 1 || grip->index() == 2)
    //{
    //    MCPoint2D startPoint = _arcModel.startPoint();
    //    MCPoint2D endPoint = _arcModel.endPoint();

    //    if (grip->index() == 1)
    //    {
    //        startPoint = pos;
    //        std::cout << "1\n";
    //    }
    //    else if (grip->index() == 2)
    //    {
    //        endPoint = pos;
    //        std::cout << "2\n";
    //    }

    //    MCCircle2D circle = MCCircle2D::from3Points(startPoint, endPoint, _arcModel.midPoint());
    //    double startAngle = MCMathUtils::normalizeAngle(MCVector2(1, 0).clockwiseAngle(startPoint - circle.center()));
    //    double endAngle = MCMathUtils::normalizeAngle(MCVector2(1, 0).clockwiseAngle(endPoint - circle.center()));

    //    _arcModel = MCArc2D(circle.center(), circle.radius(), startAngle, endAngle);
    //}

    else if (grip->index() == 3)
    {
        double rad = _arcModel.center().distanceTo(pos);
        _arcModel = MCArc2D(_arcModel.center(), rad, _arcModel.startAngle(), _arcModel.endAngle());
    }

    resetGrips();
}

void MCArcVisual::resetGrips()
{
    gripPoints[0]->update(_arcModel.center());
    gripPoints[1]->update(_arcModel.startPoint());
    gripPoints[2]->update(_arcModel.endPoint());
    gripPoints[3]->update(_arcModel.midPoint());
}

MCArc2D MCArcVisual::transformed() const
{
    MCPoint2D center = presenter->screenToWorld(_arcModel.center());
    double radius = _arcModel.radius() / presenter->scale();

    return MCArc2D(center, radius, _arcModel.startAngle(), _arcModel.endAngle());
}

void MCArcVisual::initGrips()
{
    gripPoints.push_back(new MCGripPoint(this, MCGripPointType::CenterPoint, 0, _arcModel.center()));
    gripPoints.push_back(new MCGripPoint(this, MCGripPointType::StartPoint, 1, _arcModel.startPoint()));
    gripPoints.push_back(new MCGripPoint(this, MCGripPointType::EndPoint, 2, _arcModel.endPoint()));
    gripPoints.push_back(new MCGripPoint(this, MCGripPointType::MidPoint, 3, _arcModel.midPoint()));
}
